package cn.green.config;

import cn.green.captcha.filter.VerificationCodeFilter;
import cn.green.components.dao.SysPersistentLoginDao;
import cn.green.components.service.DefaultUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


/**
 * security的核心配置类
 */
//@Configuration    因为@EnableWebSecurity注解中已经包含@Configuration注解，所以不在需要
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SavedRequestAwareAuthenticationSuccessHandler successHandler;//登陆成功处理器

    @Autowired
    private SimpleUrlAuthenticationFailureHandler failureHandler;//登录失败处理器

    @Autowired
    private AuthenticationProvider provider;//权限认证服务（自己定义的）

    @Autowired
    private UserDetailsService userDetailsService;//用户信息服务

    @Autowired
    private SysPersistentLoginDao sysPersistentLoginDao;//登录信息服务dao

    /**
     * 配置用户存储方案
     *  内存用户存储
     *  数据库用户存储
     *  LDAP用户存储
     *  自定义用户存储
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //1.spring-security提供的内存用户存储
        /*InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> configurer = auth.inMemoryAuthentication().passwordEncoder(passwordEncoder());
        configurer.withUser("account_a").password("123").roles("ADMIN")
                .and()
                .withUser("account_b").password("123").roles("USER");*/
        //2.使用用户自定义的provider
        auth.authenticationProvider(provider);
    }

    /**
     * 配置规则
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().loginPage("/loginView")//设置自定义登录页面url
                .loginProcessingUrl("/doLogin") //设置登录提交url
                //.successHandler(successHandler)//设置登录成功处理器
                .failureUrl("/loginError")      //设置登录失败处理器
                //.failureHandler(failureHandler)  //表单登录失败时跳转的url
                .successForwardUrl("/loginSuccess")//设置登录成功时跳转的url，
                .permitAll()//permitAll()表示以上的url都不需要验证
                .and()//并且
                .authorizeRequests()//url拦截注册器
                //.antMatchers("/mainPage")//mainPage资源
                //.permitAll()//以上url资源不需要验证
                .antMatchers("/admin/**").hasRole("ADMIN")//给资源(/admin/**)添加访问权限(ADMIN)
                .antMatchers("/user/**").hasRole("USER")//给资源(/user/**)添加访问权限(USER)
                .antMatchers("/app/**").permitAll()//给资源(/app/**)添加所有权限
                .anyRequest()//任何的请求
                .authenticated()//都需要认证
                .and()//并且
                .csrf().disable();//关闭跨域伪造防护功能
        //将图形验证码过滤器加入到UsernamePasswordAuthenticationFilter之前
        http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
        //注销逻辑
        http.logout()
                .logoutUrl("/simpleLogout")//设置注销请求url
                //.logoutSuccessUrl("/simpleLogoutSuccess")//设置注销成功路由
                //.invalidateHttpSession(true)//使session失效
                .deleteCookies("remember-me", "JSESSIONID");//删除cookie
               // .logoutSuccessHandler(null)//设置注销成功处理器

        //散列加密令牌方案（浏览器记住用户名和密码并且自动登录）
        /*http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")//给资源(/admin/**)添加访问权限(ADMIN)
                .antMatchers("/user/**").hasRole("USER")//给资源(/user/**)添加访问权限(USER)
                .antMatchers("/app/**").permitAll()//给资源(/app/**)添加所有权限
                .anyRequest().authenticated()
                .and().csrf().disable()
                //实现记住密码并且可以自动登录(散列加密方案-最简单的一种)
                .formLogin().and().rememberMe().userDetailsService(userDetailsService);*/
        //持久化令牌方案（浏览器记住用户名和密码并且自动登录）
        /*http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")//给资源(/admin/**)添加访问权限(ADMIN)
                .antMatchers("/user/**").hasRole("USER")//给资源(/user/**)添加访问权限(USER)
                .antMatchers("/app/**").permitAll()//给资源(/app/**)添加所有权限
                .anyRequest().authenticated()
                .and().csrf().disable()
                .formLogin()
                .loginProcessingUrl("/doLogin") //设置登录提交url
                .successHandler(successHandler)//设置登录成功处理器
                //.failureUrl("/loginError")      //设置登录失败处理器
                .failureHandler(failureHandler)  //表单登录失败时跳转的url
                //.successForwardUrl("/loginSuccess")//设置登录成功时跳转的url，
                .permitAll()//permitAll()表示以上的url都不需要验证
                .and().rememberMe().userDetailsService(userDetailsService)
                //持久化令牌方案
                .tokenRepository(sysPersistentLoginDao);*/
    }



    /**
     * 配置规则
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        //配置放行路径
        web.ignoring().
                //放行静态资源
                antMatchers("/js/**", "/css/**", "/fonts/**", "/images/**","/lib/**").
                //放行登录Url
                antMatchers("/loginView")
                //放行注销成功重定向url
                //.antMatchers("/simpleLogoutSuccess")
                //放行注销请求url
                .antMatchers("/simpleLogout")
                //放行图形码生成url
                .antMatchers("/captcha.jpg");
    }

    /**
     * 指定密码编码器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
}
